feat(cms-189): installable MDCMS skill pack + non-interactive mdcms init#102
feat(cms-189): installable MDCMS skill pack + non-interactive mdcms init#102
Conversation
…cms init` Ships a 9-skill installable pack under `skills/<slug>/SKILL.md`, distributable via `npx skills add Blazity/mdcms` (skills.sh CLI). A master orchestrator (`mdcms-setup`) detects repo state and routes to focused skills for self-hosting, brownfield/greenfield init, schema refinement, Studio embed, SDK integration, custom MDX components, and day-to-day sync. To make skills drivable without TTY prompts, `mdcms init` gains a non-interactive mode: `-y` / `--yes` / `--non-interactive`, plus `--directory`, `--directories`, `--default-locale`, `--no-import`, `--no-git-cleanup`, `--no-example-post`. Missing required inputs surface as `INIT_MISSING_INPUT` instead of hanging on a prompt. Existing interactive behavior is unchanged. - apps/cli/src/lib/init.ts: flag parser + value resolution order - apps/cli/src/lib/init.test.ts: +11 tests covering parser and flow - docs/specs/SPEC-008: documents new flags and value resolution order - skills/: new top-level distributable pack with README + 9 SKILL.md files
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a non-interactive mode to Changes
Sequence DiagramsequenceDiagram
actor User
participant CLI as CLI Process
participant Parser as Argument Parser
participant Validator as Input Validator
participant Discovery as Content Discovery
participant Server as Remote API
participant FS as File System
User->>CLI: run `npx mdcms init --non-interactive ...`
CLI->>Parser: parseInitOptions(args)
Parser-->>CLI: InitFlagOptions
CLI->>Validator: resolve/validate server, project, environment, api-key
alt missing required input in non-interactive
Validator-->>CLI: RuntimeError (INIT_MISSING_INPUT)
CLI-->>User: exit code 1, stderr message
else inputs present
CLI->>Discovery: find content directories & locales
Discovery-->>Validator: available dirs/locales
Validator->>CLI: validate --directory(s), --default-locale
CLI->>FS: write `mdcms.config.ts` (overwrite if non-interactive)
alt --no-import not set
CLI->>Server: import content (POSTs)
Server-->>CLI: import results, manifest data
CLI->>FS: write manifest
else --no-import set
CLI-->>CLI: skip import and manifest write
end
alt --no-example-post not set
CLI->>FS: scaffold `example.md`
end
CLI-->>User: exit code 0, success output
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/cli/src/lib/init.ts (1)
1077-1081:⚠️ Potential issue | 🟡 MinorDon’t announce
example.mdwhen--no-example-postskipped it.
scaffoldedTypeis set for every empty-repo init, so the outro currently says the example post was created even when lines 650-667 intentionally skipped writing it. Gate this message on actual file creation to keep non-interactive logs accurate.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/cli/src/lib/init.ts` around lines 1077 - 1081, The outro always reports "Example post created" because it checks scaffoldedType which is set for every init; instead, gate the stdout.write on whether the example file was actually created: add a boolean (e.g., exampleCreated) that is set to true where the example post write occurs (the branch that currently writes the example file) and set false when the --no-example-post path skips it, then change the final message that uses scaffoldedType/selectedDirectories to only run if exampleCreated is true; reference the existing symbols scaffoldedType, selectedDirectories and the example-file write branch to locate where to set and check exampleCreated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/cli/src/lib/init.ts`:
- Around line 617-628: The code path handling empty repos only uses
initOpts.directories[0] and silently drops additional repeatable --directory
values; update the logic in the branch that checks dirGroups.size === 0 to
either iterate over initOpts.directories and set selectedDirectories to all
provided values (so every requested directory is scaffolded), or explicitly
reject multiple values when initOpts.nonInteractive is true by validating
initOpts.directories.length and throwing/printing an error; modify the block
referencing initOpts.directories, dirName, selectedDirectories and the
prompter.text fallback to preserve or validate all entries rather than only
using the first one.
- Around line 61-76: The parsing logic currently allows empty inline values for
flags like --directory, --directories, and --default-locale to slip through;
update the flag-handling code so inline empty values are validated the same as
space-separated forms by reusing or mirroring readInitFlagValue's check: when
you detect a flag token that may contain an '=' (e.g., '--directory=' or
'--default-locale='), treat an empty string after '=' as missing and throw the
same RuntimeError({ code: "INVALID_INPUT", message: `Flag "${flag}" requires a
value.`, statusCode: 400, details: { flag } }) used in readInitFlagValue;
alternatively call readInitFlagValue for space-separated cases and add a utility
that validates and rejects '' for '='-style tokens in the code paths that
currently handle --directory, --directories, and --default-locale (also apply
the same change to the other flag parsing block mentioned around the other
parsing function).
In `@skills/mdcms-brownfield-init/SKILL.md`:
- Around line 66-68: The line "Creates (or joins) the project and environment on
the server." incorrectly claims reuse; either remove "or joins" or explicitly
document the exact precondition/recovery path for the init command: state that
init will attempt to create the project/environment and will exit with an error
on project-create 409, describe what the caller should do on that error (e.g.,
manually join or pass an explicit flag), and reference the init behavior and the
project-create 409 response so readers know the expected flow.
In `@skills/mdcms-content-sync-workflow/SKILL.md`:
- Around line 92-120: The workflow's MDCMS push step uses the interactive-safe
command `npx mdcms push --validate`, which will skip new/deleted candidates in
non-interactive CI and can cause schema sync failures; update the `MDCMS push`
job to run a headless-safe command such as `npx mdcms push --validate --force`
(and add any CLI flag your tool uses for non-interactive confirmation like
`--yes` or `--confirm` if available) so pushes on `content/**` or
`mdcms.config.ts` changes apply created/deleted items and schema updates
reliably; modify the `run:` line under the `MDCMS push` step to include these
flags.
- Around line 135-138: Update the SKILL.md bullet that instructs readers to
"check `mdcms push --help` for the current deletion flag" because the CLI
doesn't expose a dedicated deletion flag; instead, reword the text to explain
that deletions are handled interactively by `mdcms push` (it will classify "both
modified" or prompt before deleting) and mention the actual available flags
(`--force`, `--dry-run`, `--validate`, `--published`, `--sync-schema`) and how
`--force` affects deletion behavior (non-interactive overwrite). Refer to the
`mdcms push` command and the `--force`/`--dry-run` flags when updating the
paragraph.
In `@skills/mdcms-sdk-integration/SKILL.md`:
- Around line 55-65: Replace the incorrect SDK calls and shape assumptions: use
the SDK methods cms.get(type, input) and cms.list(type, input?) instead of
getDocument/listDocuments, and update any downstream usage to expect the
paginated envelope returned by list (access the items via the .data property,
e.g., iterate over posts.data rather than posts); update examples that showed
const about = ... and const posts = ... to call cms.get("page", { path: "about"
}) and cms.list("post", { limit: 20 }) semantics and adjust subsequent code to
use the list response's data field.
In `@skills/mdcms-self-host-setup/SKILL.md`:
- Around line 40-43: The checklist uses the wrong S3 env-var prefix
`MDCMS_S3_*`; update the doc to reference the correct storage env names `S3_*`
(e.g., replace any occurrence of `MDCMS_S3_*` with `S3_*`) so they match the
server/compose contract; double-check related mentions (the checklist item
listing `Database credentials`, `S3/MinIO credentials`, `Auth provider
settings`, and `MDCMS_STUDIO_ALLOWED_ORIGINS` / `<Studio />`) and adjust only
the S3 variable names to `S3_*` while leaving other env names unchanged.
In `@skills/mdcms-setup/SKILL.md`:
- Around line 36-44: The repo-scan heuristic that runs the find command will
pick up the skill pack’s own SKILL.md and misclassify empty repos as brownfield;
update the detection used before invoking
mdcms-brownfield-init/mdcms-greenfield-init to exclude skills/ and other
docs-only paths (e.g., skills/*/SKILL.md, docs/, .github/) or restrict the
search to likely content roots (e.g., content/, pages/, docs/content/) so only
true user-managed Markdown/MDX files trigger mdcms-brownfield-init; ensure the
same exclusion logic is applied where the check is repeated (lines referenced
around the find invocation and the branch that calls
mdcms-brownfield-init/mdcms-greenfield-init).
---
Outside diff comments:
In `@apps/cli/src/lib/init.ts`:
- Around line 1077-1081: The outro always reports "Example post created" because
it checks scaffoldedType which is set for every init; instead, gate the
stdout.write on whether the example file was actually created: add a boolean
(e.g., exampleCreated) that is set to true where the example post write occurs
(the branch that currently writes the example file) and set false when the
--no-example-post path skips it, then change the final message that uses
scaffoldedType/selectedDirectories to only run if exampleCreated is true;
reference the existing symbols scaffoldedType, selectedDirectories and the
example-file write branch to locate where to set and check exampleCreated.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: bbcce7f5-f318-4670-82fd-a0b4caa1d223
📒 Files selected for processing (13)
apps/cli/src/lib/init.test.tsapps/cli/src/lib/init.tsdocs/specs/SPEC-008-cli-and-sdk.mdskills/README.mdskills/mdcms-brownfield-init/SKILL.mdskills/mdcms-content-sync-workflow/SKILL.mdskills/mdcms-greenfield-init/SKILL.mdskills/mdcms-mdx-components/SKILL.mdskills/mdcms-schema-refine/SKILL.mdskills/mdcms-sdk-integration/SKILL.mdskills/mdcms-self-host-setup/SKILL.mdskills/mdcms-setup/SKILL.mdskills/mdcms-studio-embed/SKILL.md
CLI: - parseInitOptions: reject empty inline flag values (`--directory=`, `--directories=`, `--default-locale=`) with the same error interactive space-separated forms already use. - Empty-repo scaffold path: reject multiple `--directory` values since scaffolding only supports one starter directory. - Outro "Example post created" now gated on a real `exampleCreated` boolean rather than the presence of a scaffolded type, so `--no-example-post` no longer advertises a file it never wrote. - Tests: +3 cases covering inline empty rejection, multiple-directory rejection in empty-repo mode, and the outro suppression. Skills: - mdcms-brownfield-init: drop "or joins" claim. Init creates; server returns 409 on conflict and init exits. Added an "Attaching to an existing project" subsection covering the recovery path. - mdcms-content-sync-workflow: CI example now runs with `--force` and `--sync-schema` alongside `--validate`, because push silently skips new/deleted candidates in non-interactive mode without `--force`. Deletion note rewritten to name the real push flag surface (`--force`, `--dry-run`, `--validate`, `--published`, `--sync-schema`) — there is no dedicated deletion flag. - mdcms-sdk-integration: replace invented `getDocument`/`listDocuments` with the actual `cms.get(type, input)` / `cms.list(type, input)`; list examples iterate the paginated envelope via `response.data`; removed the invented `path` parameter on `get` in favor of `id` / `slug` per SPEC-008. - mdcms-self-host-setup: fix S3 env var names — prefix is `S3_*`, not `MDCMS_S3_*`, matching `.env.example`. - mdcms-setup: Phase 2 `find` command now excludes `skills/`, `docs/`, `apps/docs/`, `.github/`, and repo-level `README`/ `CHANGELOG`/`LICENSE`/`SKILL.md`, so installing this skill pack into a repo doesn't self-trigger the brownfield path.
Summary
skills/<slug>/SKILL.md, distributed via skills.sh —npx skills add Blazity/mdcms. Works cross-agent (Claude Code, Cursor, Gemini, Codex, Copilot, and 40+ others).mdcms-setup) detects repo state and routes to the focused skill for each phase: self-host, brownfield vs greenfield init, schema refine, Studio embed, SDK integration, MDX components, day-to-day sync.mdcms initgains a non-interactive mode so AI agents (and CI) can drive it end-to-end:-y/--yes/--non-interactive, plus--directory,--directories,--default-locale,--no-import,--no-git-cleanup,--no-example-post. Missing required input surfaces asINIT_MISSING_INPUTinstead of hanging on a TTY prompt.mdcms initbehavior is unchanged. Value resolution order: flag → env var → config → stored credential → prompt (skipped in non-interactive).Skills in the pack
mdcms-setupmdcms-self-host-setupmdcms-brownfield-initmdcms init --non-interactivemdcms-greenfield-initmdcms-schema-refinedefineType/ Zod /reference()+schema syncmdcms-studio-embed<Studio />catch-all route in host appmdcms-sdk-integration@mdcms/sdkfetch, drafts vs published, SSRmdcms-mdx-componentsmdcms-content-sync-workflowpull/push+ CI automationSpec delta
docs/specs/SPEC-008— documents the non-interactive surface (flag table, value resolution order,INIT_MISSING_INPUTerror) alongside the existing interactive wizard. No Studio / backend contract changes; noapps/studio-reviewimpact.Test plan
bun test --cwd apps/cli ./src/lib/init.test.ts— 18/18 pass (11 new, 7 pre-existing).bun test --cwd apps/cli ./src— 203/203 pass.bun x prettier --check <changed paths>— clean.bun run check— CLI typecheck clean;packages/studiohas a pre-existing@tiptap/pmtype-resolution failure reproducible on untouchedorigin/main, unrelated to this PR.mdcms init --non-interactive --server-url … --project … --environment … --api-key … --directory …against a dev backend and confirm config + schema + import complete without any prompt.npx skills addfrom a local checkout into~/.claude/skills/and verify the master orchestrator triggers on "set up MDCMS".Notes for reviewers
apps/studio-exampleas the source of truth for Studio embed / MDX component wiring rather than inlining possibly-drifting code snippets. Corrections welcome if I've mis-stated any current contract detail.Closes CMS-189.
Summary by CodeRabbit
New Features
Behavior Changes / Error Handling
Tests
Documentation